package com.ccb.testcenter.configuration;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import com.ccb.testcenter.config.entity.BeanConfig;
import com.ccb.testcenter.config.entity.ConstantConfig;
import com.ccb.testcenter.config.entity.CustomRuleConfig;
import com.ccb.testcenter.config.entity.FilterConfig;
import com.ccb.testcenter.config.entity.MappingConfig;
import com.ccb.testcenter.config.entity.ParamConfig;
import com.ccb.testcenter.config.entity.RequestConfig;
import com.ccb.testcenter.config.entity.ResponseConfig;
import com.ccb.testcenter.config.entity.SegmentConfig;
import com.ccb.testcenter.servicemaping.Trcd;

public class XMLAthenaBuilder {
	private XPathParser parser;
	protected final Configuration configuration;
//	private DefaultMappingFactory defaultMappingFactory;
//	private DefaultRouterFactory defaultRouterFacctory;
//	private DefaultFilterFactory defaultFilterFactory;
//	private DefaultSegmentFactory defaultSegmentFactory;
//	private DefaultCustomRuleFactory defaultCustomRuleFactory;
	
	
	
	public XMLAthenaBuilder(InputStream inputStream) {
		configuration = new Configuration();
		this.parser = new XPathParser(inputStream, false);
//		defaultRouterFacctory=new DefaultRouterFactory();
//		defaultFilterFactory=new DefaultFilterFactory();
//		defaultSegmentFactory=new DefaultSegmentFactory(configuration);
//		defaultCustomRuleFactory=new DefaultCustomRuleFactory();
		
//		defaultMappingFactory=new DefaultMappingFactory(configuration);
		
	}
	
	public XMLAthenaBuilder(InputStream inputStream,Configuration conf) {
		configuration = conf;
		this.parser = new XPathParser(inputStream, false);
//		defaultRouterFacctory=new DefaultRouterFactory();
//		defaultFilterFactory=new DefaultFilterFactory();
//		defaultSegmentFactory=new DefaultSegmentFactory(configuration);
//		
//		defaultMappingFactory=new DefaultMappingFactory(configuration);
	}
	public void parse() {
		parseConfiguration(parser.evalNode("/athena"));
	}

	private void parseConfiguration(XNode root) {
		try {
			parseBean(root.evalNodes("bean"));
			parseConstantConfig(root.evalNodes("constant"));
			parseFilters(root.evalNode("filters"));
			parseSegments(root.evalNode("segments"));
			parseSegmentGroup(root.evalNodes("segment-groups/segment-group"));
			parseMappings(root.evalNodes("mappings/mapping"));
			parseCustomRuleConfig(root.evalNodes("custom-rules/custom-rule"));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	private void parseConstantConfig(List<XNode> ConstantConfigList) {
		for (XNode child : ConstantConfigList) {
			if ("constant".equals(child.getName())) {
				ConstantConfig constantConfig=new ConstantConfig();
				String name = child.getStringAttribute("name");
				String value = child.getStringAttribute("value");
				constantConfig.setName(name);
				constantConfig.setValue(value);
				configuration.addConstantConfig(name, constantConfig);
			}
		}
		
	}
	
	private void parseBean(List<XNode> beanConfigList) {
		for (XNode child : beanConfigList) {
			if ("bean".equals(child.getName())) {
				BeanConfig beanConfig = new BeanConfig();
				String name = child.getStringAttribute("name");
				String type = child.getStringAttribute("type");
				String clazz = child.getStringAttribute("class");
				beanConfig.setName(name);
				beanConfig.setClazz(clazz);
				beanConfig.setType(type);
//				try {
//					IRouter iRouter=defaultRouterFacctory.buildRouter(router);
//					configuration.iRouterMap.put(id, iRouter);
//				} catch (Exception e) {
//					e.printStackTrace();
//				}
				configuration.addBeanConfig(name, beanConfig);
			}
		}
	}

	private void parseFilters(XNode filters) throws Exception {
		for (XNode child : filters.getChildren()) {
			if ("filter".equals(child.getName())) {
				FilterConfig filter = new FilterConfig();
				String id = child.getStringAttribute("id");
				String className = child.getStringAttribute("class");
				filter.setId(id);
				filter.setClazz(className);
//				IFilter iflter=defaultFilterFactory.buildFilter(filter);
//				configuration.iFilterMap.put(id, iflter);
//				configuration.filterConfigMap.put(id, filter);
			}
		}
	}

	private void parseSegments(XNode segments) {
		
		for (XNode child : segments.getChildren()) {
			if ("segment".equals(child.getName())) {
				SegmentConfig segmentConfig = new SegmentConfig();
				String name = child.getStringAttribute("name");
				String root = child.getStringAttribute("root");
				String file = child.getStringAttribute("file");
				String sheetName = child.getStringAttribute("sheet-name");
				segmentConfig.setName(name);
				segmentConfig.setFile(file);
				segmentConfig.setRoot(root);
				segmentConfig.setSheetName(sheetName);
//				try {
//					Segment segment = defaultSegmentFactory.buildSegment(segmentConfig);
//					configuration.segmentMap.put(name, segment);
//				} catch (Exception e) {
//					e.printStackTrace();
//				}
				configuration.segmentConfigMap.put(name, segmentConfig);
			}
		}
	}

	private void parseSegmentGroup(List<XNode> segmentGroups) {
		for (XNode segmentGroup : segmentGroups) {
			String id = segmentGroup.getStringAttribute("id");
			List<SegmentConfig> segmentList = new ArrayList<>();
			for (XNode child : segmentGroup.getChildren()) {
				segmentList = new ArrayList<>();
				if ("segment-group".equals(child.getName())) {
					String segmentRef = child.getStringAttribute("segment-ref");
					if (configuration.segmentConfigMap.containsKey(segmentRef)) {
						segmentList.add(configuration.segmentConfigMap.get(segmentRef));
					}
				}
			}
			if (!id.isEmpty() && segmentList != null) {
				configuration.segmentConfigGroupMap.put(id, segmentList);
			}

		}
	}

	private void parseMappings(List<XNode> mappings) {
		for (XNode mappingNode : mappings) {
			MappingConfig mappingConfig = new MappingConfig();
			
			String name = mappingNode.getStringAttribute("name");
			String source = mappingNode.getStringAttribute("source");
			List<FilterConfig> filterList = parseMappingFilter(mappingNode.evalNode("filters"));
			RequestConfig requestConfig = parseMappingRequest(mappingNode.evalNode("request"));
			ResponseConfig responseConfig = parseMappingResponse(mappingNode.evalNode("response"));
			Trcd trcd = new Trcd();
			trcd.setSourceCode(source);
			trcd.setDistinationCode(name);
			
			mappingConfig.setFilters(filterList);
			mappingConfig.setRequestConfig(requestConfig);
			mappingConfig.setResponseConfig(responseConfig);
			mappingConfig.setName(name);
			mappingConfig.setSource(source);
			StringBuilder key = new StringBuilder();
			key.append(name).append("-").append(source);
			// mappingMap.put(key.toString(), mapping);
//			Mapping mapping = defaultMappingFactory.buildMapping(mappingConfig);
//			configuration.mappingConfigMap.put(key.toString(), mappingConfig);
//			configuration.addMapping(trcd, mapping);
			// mapping.setFilters(filterList);
			// for(XNode child:mapping.getChildren()){
			//
			// }

		}
	}

	private List<FilterConfig> parseMappingFilter(XNode xNode) {
		List<FilterConfig> list = null;
		if (xNode != null && xNode.getChildren() != null && xNode.getChildren().size() > 0) {
			list = new ArrayList<>();
			for (XNode child : xNode.getChildren()) {
				if ("filter-ref".equals(child.getName())) {
					String filterRef = child.getStringBody();
					list.add(configuration.filterConfigMap.get(filterRef));
				}
			}
		}
		return list;
	}

	private RequestConfig parseMappingRequest(XNode xNode) {
		RequestConfig requestConfig = null;
		if (xNode != null) {
			requestConfig = new RequestConfig();
			for (XNode child : xNode.getChildren()) {
				if ("convert".equals(child.getName())) {
					requestConfig.setConvert(child.getBooleanBody());
				}
				if ("segments".equals(child.getName())) {
					LinkedList<SegmentConfig> list = parseMappingSegmentRef(child.evalNodes("segment-ref"));
					requestConfig.setSegments(list);
				}

			}
		}
		
		return requestConfig;
	}

	private ResponseConfig parseMappingResponse(XNode xNode) {
		ResponseConfig response = null;
		if (xNode != null) {
			response = new ResponseConfig();
			for (XNode child : xNode.getChildren()) {
				if ("convert".equals(child.getName())) {
					response.setConvert(child.getBooleanBody());
				}
				if ("segments".equals(child.getName())) {
					LinkedList<SegmentConfig> list = parseMappingSegmentRef(child.evalNodes("segment-ref"));
					response.setSegments(list);
				}

			}
		}

		return response;
	}

	private LinkedList<SegmentConfig> parseMappingSegmentRef(List<XNode> segmentList) {
		LinkedList<SegmentConfig> list = null;
		if (segmentList.size() > 0) {
			list = new LinkedList<>();
		}
		for (XNode child : segmentList) {
			if ("segment-ref".equals(child.getName())) {
				String segmentRef = child.getStringBody();
				if (configuration.segmentConfigMap.containsKey(segmentRef)) {
					list.add(configuration.segmentConfigMap.get(segmentRef));
				}
			}
		}
		return list;
	}
	private void parseCustomRuleConfig(List<XNode> customRuleList) throws Exception {
		for (XNode child : customRuleList) {
			if ("custom-rule".equals(child.getName())) {
				CustomRuleConfig crc=new CustomRuleConfig();
				String id = child.getStringAttribute("id");
				String clazz=child.getStringAttribute("class");
				String method=child.getStringAttribute("method");
				List<ParamConfig> plist=parseParamConfig(child.evalNodes("params/param"));
				crc.setId(id);
				crc.setClazz(clazz);
				crc.setList(plist);
				crc.setMethod(method);
				configuration.customRuleConfigMap.put(id, crc);
//				CustomRule customRule=defaultCustomRuleFactory.buildCustomRule(crc);
//				configuration.addCustomRule(id, customRule);
			}
			
		}
	}
	
	private List<ParamConfig> parseParamConfig(List<XNode> paramList) {
		List<ParamConfig> list = null;
		if (paramList.size() > 0) {
			list = new ArrayList<>();
		}
		for (XNode child : paramList) {
			ParamConfig pc=new ParamConfig();
			String defaultValue=child.getStringAttribute("defaultValue");
			String type=child.getStringAttribute("type");
			String required=child.getStringAttribute("required");
			String notNull=child.getStringAttribute("not-null");
			pc.setDefaultValue(defaultValue);
			pc.setType(type);
			pc.setRequired(required);
			pc.setNotNull(notNull);
			list.add(pc);
		}
		
		return list;
	}
}
